package cn.stylefeng.guns.main.modular.county.utils;

import cn.hutool.core.date.DateUtil; // 导入 cn.hutool.core.date.DateUtil，提供了日期时间相关的实用方法
import cn.stylefeng.guns.main.modular.county.modal.WeekListVo; // 导入自定义的 WeekListVo 类
import lombok.SneakyThrows; // Lombok 注解，用于简化异常处理

import java.text.ParseException; // 用于日期解析异常
import java.text.SimpleDateFormat; // 用于日期格式化和解析
import java.time.LocalDateTime; // Java 8+ 日期时间 API
import java.time.ZoneId; // Java 8+ 时区 API
import java.util.*; // 集合和日期相关的工具类

/**
 * @Description: 时间工具类
 * @author: XuMing
 * @Date: 2022/4/9
 * @Version: 1.0.0
 */
@SuppressWarnings("unused") // 抑制“未使用”警告
public class DateUtils {

    // ==== 常量：日期格式化器 (注意：SimpleDateFormat 非线程安全，建议使用 ThreadLocal 或 Java 8 DateTimeFormatter) ====
    // 为了兼容原始代码结构，在此保留使用 SimpleDateFormat。在实际项目中，应进行线程安全处理。
    private static final String YYYYMMDD_PATTERN = "yyyyMMdd";
    private static final String YYYYMM_PATTERN = "yyyyMM";

    /**
     * 获取 yyyyMMdd 格式日期字符串的友好展示格式 (yyyy年MM月dd日)。
     * 如果解析失败，则直接返回原始字符串。
     *
     * @param acctMonth 期望格式为 "yyyyMMdd" 的日期字符串。
     * @return 格式化后的日期字符串，例如 "2023年01月01日"。如果解析失败，返回原始 {@code acctMonth}。
     */
    public static String getFormat(String acctMonth) {
        // 原实现：
        // SimpleDateFormat monthFormat = new SimpleDateFormat(YYYYMMDD_PATTERN); // 用于解析 "yyyyMMdd"
        // SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy年MM月dd日"); // 用于格式化 "yyyy年MM月dd日"
        // try {
        //     return sdf1.format(monthFormat.parse(acctMonth));
        // } catch (ParseException e) {
        //     e.printStackTrace();
        //     return acctMonth;
        // }
        // 优化实现：使用 ZhyyDateUtil 进行解析与格式化（线程安全的 java.time 实现）
        String res = ZhyyDateUtil.formatDayToChinese(acctMonth);
        return res == null ? acctMonth : res;
    }

    /**
     * 获取 yyyyMM 格式月份字符串的友好展示格式 (yyyy年MM月)。
     * 如果解析失败，则直接返回原始字符串。
     *
     * @param acctMonth 期望格式为 "yyyyMM" 的月份字符串。
     * @return 格式化后的月份字符串，例如 "2023年01月"。如果解析失败，返回原始 {@code acctMonth}。
     */
    public static String getFormatM(String acctMonth) {
        // 原实现：
        // SimpleDateFormat monthFormat = new SimpleDateFormat(YYYYMM_PATTERN);
        // SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy年MM月");
        // try {
        //     return sdf1.format(monthFormat.parse(acctMonth));
        // } catch (ParseException e) {
        //     e.printStackTrace();
        //     return acctMonth;
        // }
        // 优化实现：委托 ZhyyDateUtil
        String res = ZhyyDateUtil.formatMonthToChinese(acctMonth);
        return res == null ? acctMonth : res;
    }

    /**
     * **注意：此方法功能与名称不符。实际功能是获取当前日期所在月份的上一个月的年份和月份 (yyyyMM)。**
     *
     * 该方法首先将Calendar设置为当前时间，然后执行一系列操作：
     * 1. {@code cal.add(Calendar.MONTH, 0);}: 无效操作，不会改变月份。
     * 2. {@code cal.set(Calendar.DAY_OF_MONTH, 1);}: 将日期设置为当前月份的第一天。
     * 3. {@code cal.add(Calendar.DATE, -1);}: 将日期减去一天，这会使得Calendar指向**上一个月的最后一天**。
     * 最后格式化为 "yyyyMM" 字符串，从而得到上一个月的年月。
     *
     * @return 当前日期的上一个月份的字符串表示，格式为 "yyyyMM"。
     */
    public static String getMonth() {
        // 原实现：
        // SimpleDateFormat monthFormat = new SimpleDateFormat(YYYYMM_PATTERN);
        // Calendar cal = Calendar.getInstance();
        // cal.setTime(new Date());
        // cal.add(Calendar.MONTH, 0);
        // cal.set(Calendar.DAY_OF_MONTH, 1);
        // cal.add(Calendar.DATE, -1);
        // return monthFormat.format(cal.getTime());
        // 优化实现：委托 ZhyyDateUtil
        String res = ZhyyDateUtil.getPreviousMonth();
        return res == null ? new java.text.SimpleDateFormat(YYYYMM_PATTERN).format(new Date()) : res;
    }

    /**
     * **注意：此方法功能与名称不符。实际功能是获取当前日期的年份和月份 (yyyyMM)。**
     *
     * @return 当前月份的字符串表示，格式为 "yyyyMM"。
     */
    public static String getMonth1() {
        // 原实现：
        // SimpleDateFormat monthFormat = new SimpleDateFormat(YYYYMM_PATTERN);
        // Calendar cal = Calendar.getInstance();
        // cal.setTime(new Date());
        // return monthFormat.format(cal.getTime());
        // 优化实现：委托 ZhyyDateUtil
        String res = ZhyyDateUtil.getCurrentMonth();
        return res == null ? new java.text.SimpleDateFormat(YYYYMM_PATTERN).format(new Date()) : res;
    }

    /**
     * 获取给定月份字符串 {@code acctMonth} 的下一个月份的年份和月份 (yyyyMM)。
     * 如果 {@code acctMonth} 解析失败，则使用当前日期作为基准。
     *
     * @param acctMonth 期望格式为 "yyyyMM" 的月份字符串。
     * @return 下一个月份的字符串表示，格式为 "yyyyMM"。
     */
    public static String getNextMonth(String acctMonth) {
        // 原实现：
        // SimpleDateFormat monthFormat = new SimpleDateFormat(YYYYMM_PATTERN);
        // Date date;
        // try { date = monthFormat.parse(acctMonth); } catch (ParseException e) { e.printStackTrace(); date = new Date(); }
        // Calendar cal = Calendar.getInstance(); cal.setTime(date); cal.add(Calendar.MONTH, 1); return monthFormat.format(cal.getTime());
        // 优化实现：优先委托 ZhyyDateUtil，失败时回退到原实现
        try {
            String res = ZhyyDateUtil.getNextMonth(acctMonth);
            if (res != null) return res;
        } catch (Exception ignored) {
        }
        // 回退：解析并计算
        SimpleDateFormat monthFormat = new SimpleDateFormat(YYYYMM_PATTERN);
        Date date;
        try {
            date = monthFormat.parse(acctMonth);
        } catch (ParseException e) {
            date = new Date();
        }
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.MONTH, 1);
        return monthFormat.format(cal.getTime());
    }

    /**
     * 获取从指定月份开始，到当前月份（或未来某个月份，取决于j的值）的一个月份列表。
     * 列表中的每个月份都是其对应日期所在月份的**前一个月份的最后一天**的年份和月份 (yyyyMM)。
     * <p>
     * **注意：此方法的逻辑有些复杂且命名容易混淆。**
     * 它的循环条件是 {@code i <= 1}，且 {@code i} 从 {@code j} 开始。
     * 循环体内，会取 {@code date} 加上 {@code i} 个月后的月份的**前一个月的最后一天**的年月。
     * 示例：如果 {@code acctMonth} 是 "202310"，{@code j=0}，那么 i 的取值是 0 和 1。
     *   - 当 i=0 时，结果是 "202309" (202310 的前一个月)
     *   - 当 i=1 时，结果是 "202310" (202311 的前一个月)
     *
     * @param acctMonth 期望格式为 "yyyyMM" 的起始月份字符串。
     * @param j         循环的起始索引，通常为负数或0，表示计算之前或当前的几个月。
     * @return 包含目标月份字符串的列表，格式为 "yyyyMM"。
     */
    public static List<String> getMonthList(String acctMonth, int j) {
        SimpleDateFormat monthFormat = new SimpleDateFormat(YYYYMM_PATTERN);
        Date date;
        try {
            date = monthFormat.parse(acctMonth);
        } catch (ParseException e) {
            e.printStackTrace();
            date = new Date(); // 解析失败则使用当前日期
        }
        List<String> list = new ArrayList<>();
        // 循环是从 j 遍历到 1
        for (int i = j; i <= 1; i++) {
            Calendar cal = Calendar.getInstance();
            cal.setTime(date);
            cal.add(Calendar.MONTH, i); // 在原始日期基础上增加 i 个月
            cal.set(Calendar.DAY_OF_MONTH, 1); // 设置为当前计算月份的第一天
            cal.add(Calendar.DATE, -1); // 减去一天，得到当前计算月份的**前一个月的最后一天**
            list.add(monthFormat.format(cal.getTime())); // 格式化年月并添加到列表
        }
        return list;
    }

    /**
     * 获取给定月份字符串 {@code acctMonth} 的上一个月份的年份和月份 (yyyyMM)。
     * 如果 {@code acctMonth} 解析失败，则使用当前日期作为基准。
     *
     * @param acctMonth 期望格式为 "yyyyMM" 的月份字符串。
     * @return 上一个月份的字符串表示，格式为 "yyyyMM"。
     */
    public static String getLastMonth(String acctMonth) {
        // 原实现：
        // SimpleDateFormat monthFormat = new SimpleDateFormat(YYYYMM_PATTERN);
        // Date date;
        // try { date = monthFormat.parse(acctMonth); } catch (ParseException e) { e.printStackTrace(); date = new Date(); }
        // Calendar cal = Calendar.getInstance(); cal.setTime(date); cal.add(Calendar.MONTH, 0); cal.set(Calendar.DAY_OF_MONTH, 1); cal.add(Calendar.MONTH, -1); return monthFormat.format(cal.getTime());
        // 优化：委托 ZhyyDateUtil
        try {
            String res = ZhyyDateUtil.getPreviousMonth(acctMonth);
            if (res != null) return res;
        } catch (Exception ignored) {
        }
        // 回退到原实现
        SimpleDateFormat monthFormat = new SimpleDateFormat(YYYYMM_PATTERN);
        Date date;
        try {
            date = monthFormat.parse(acctMonth);
        } catch (ParseException e) {
            date = new Date();
        }
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.MONTH, 0);
        cal.set(Calendar.DAY_OF_MONTH, 1);
        cal.add(Calendar.MONTH, -1);
        return monthFormat.format(cal.getTime());
    }

    /**
     * 获取给定日期 {@code date} 所在月份的第一天的日期字符串 (yyyyMMdd)。
     *
     * @param date 输入的日期 {@code java.util.Date} 对象。
     * @return 给定日期所在月份的第一天的字符串表示，格式为 "yyyyMMdd"。
     */
    public static String getMonthStart(Date date) {
        // 原实现：
        // SimpleDateFormat sdf = new SimpleDateFormat(YYYYMMDD_PATTERN);
        // Calendar cal = Calendar.getInstance(); cal.setTime(date); cal.add(Calendar.MONTH, 0); cal.set(Calendar.DAY_OF_MONTH, 1); return sdf.format(cal.getTime());
        // 优化：委托 ZhyyDateUtil
        try {
            return ZhyyDateUtil.getMonthStartFormatted(date);
        } catch (Exception e) {
            // 回退到原实现
            SimpleDateFormat sdf = new SimpleDateFormat(YYYYMMDD_PATTERN);
            Calendar cal = Calendar.getInstance();
            cal.setTime(date);
            cal.set(Calendar.DAY_OF_MONTH, 1);
            return sdf.format(cal.getTime());
        }
    }

    /**
     * 获取给定日期字符串 {@code acctMonth} 所在月份的第一天的日期字符串 (yyyyMMdd)。
     * 如果 {@code acctMonth} 解析失败，则使用当前日期作为基准。
     *
     * @param acctMonth 期望格式为 "yyyyMMdd" 的日期字符串。
     * @return 给定日期字符串所在月份的第一天的日期字符串，格式为 "yyyyMMdd"。
     */
    public static String getMonthStart1(String acctMonth) {
        // 原实现：
        // SimpleDateFormat sdf = new SimpleDateFormat(YYYYMMDD_PATTERN); Date date; try { date = sdf.parse(acctMonth); } catch (ParseException e) { date = new Date(); } Calendar cal = Calendar.getInstance(); cal.setTime(date); cal.add(Calendar.MONTH, 0); cal.set(Calendar.DAY_OF_MONTH, 1); return sdf.format(cal.getTime());
        try {
            String res = ZhyyDateUtil.getMonthStartFormatted(acctMonth);
            if (res != null) return res;
        } catch (Exception ignored) {
        }
        // 回退到原实现
        SimpleDateFormat sdf = new SimpleDateFormat(YYYYMMDD_PATTERN);
        Date date;
        try {
            date = sdf.parse(acctMonth);
        } catch (ParseException e) {
            date = new Date();
        }
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.MONTH, 0);
        cal.set(Calendar.DAY_OF_MONTH, 1);
        return sdf.format(cal.getTime());
    }

    /**
     * 获取给定日期字符串 {@code acctMonth} 的**前一个月份**的第一天的日期字符串 (yyyyMMdd)。
     * 如果 {@code acctMonth} 解析失败，则使用当前日期作为基准。
     *
     * @param acctMonth 期望格式为 "yyyyMMdd" 的日期字符串。
     * @return 给定日期字符串前一个月份的第一天的日期字符串，格式为 "yyyyMMdd"。
     */
    public static String getMonthStart2(String acctMonth) {
        // 原实现：
        // SimpleDateFormat sdf = new SimpleDateFormat(YYYYMMDD_PATTERN); Date date; try { date = sdf.parse(acctMonth); } catch (ParseException e) { e.printStackTrace(); date = new Date(); } Calendar cal = Calendar.getInstance(); cal.setTime(date); cal.add(Calendar.MONTH, -1); cal.set(Calendar.DAY_OF_MONTH, 1); return sdf.format(cal.getTime());
        try {
            String res = ZhyyDateUtil.getPreviousMonthStartFormatted(acctMonth);
            if (res != null) return res;
        } catch (Exception ignored) {
        }
        // 回退到原实现
        SimpleDateFormat sdf = new SimpleDateFormat(YYYYMMDD_PATTERN);
        Date date;
        try {
            date = sdf.parse(acctMonth);
        } catch (ParseException e) {
            date = new Date();
        }
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.MONTH, -1);
        cal.set(Calendar.DAY_OF_MONTH, 1);
        return sdf.format(cal.getTime());
    }

    /**
     * 获取给定日期 {@code date} 所在月份的最后一天的日期字符串 (yyyyMMdd)。
     *
     * @param date 输入的日期 {@code java.util.Date} 对象。
     * @return 给定日期所在月份的最后一天的日期字符串，格式为 "yyyyMMdd"。
     */
    public static String getMonthEnd(Date date) {
        // 原实现：
        // SimpleDateFormat sdf = new SimpleDateFormat(YYYYMMDD_PATTERN); Calendar cal = Calendar.getInstance(); cal.setTime(date); cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH)); return sdf.format(cal.getTime());
        try {
            return ZhyyDateUtil.getMonthEndFormatted(date);
        } catch (Exception e) {
            SimpleDateFormat sdf = new SimpleDateFormat(YYYYMMDD_PATTERN);
            Calendar cal = Calendar.getInstance();
            cal.setTime(date);
            cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
            return sdf.format(cal.getTime());
        }
    }

    /**
     * 获取给定月份字符串 {@code acctMonth} (yyyyMM) 所在月份的最后一天的日期字符串 (yyyyMMdd)。
     * 如果 {@code acctMonth} 解析失败，则使用当前日期作为基准。
     *
     * @param acctMonth 期望格式为 "yyyyMM" 的月份字符串。
     * @return 给定月份字符串所在月份的最后一天的日期字符串，格式为 "yyyyMMdd"。
     */
    public static String getMonthEnd1(String acctMonth) {
        // 原实现：
        // SimpleDateFormat monthFormat = new SimpleDateFormat(YYYYMM_PATTERN); SimpleDateFormat sdf = new SimpleDateFormat(YYYYMMDD_PATTERN); Date date; try { date = monthFormat.parse(acctMonth); } catch (ParseException e) { e.printStackTrace(); date = new Date(); } Calendar cal = Calendar.getInstance(); cal.setTime(date); cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH)); return sdf.format(cal.getTime());
        try {
            String res = ZhyyDateUtil.getMonthEndFormatted(acctMonth);
            if (res != null) return res;
        } catch (Exception ignored) {
        }
        // 回退到原实现
        SimpleDateFormat monthFormat = new SimpleDateFormat(YYYYMM_PATTERN);
        SimpleDateFormat sdf = new SimpleDateFormat(YYYYMMDD_PATTERN);
        Date date;
        try {
            date = monthFormat.parse(acctMonth);
        } catch (ParseException e) {
            date = new Date();
        }
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
        return sdf.format(cal.getTime());
    }

    /**
     * 获取给定日期字符串 {@code acctMonth} (yyyyMMdd) 所在月份的最后一天的日期字符串 (yyyyMMdd)。
     * 如果 {@code acctMonth} 解析失败，则使用当前日期作为基准。
     *
     * @param acctMonth 期望格式为 "yyyyMMdd" 的日期字符串。
     * @return 给定日期字符串所在月份的最后一天的日期字符串，格式为 "yyyyMMdd"。
     */
    public static String getMonthEnd2(String acctMonth) {
        // 原实现：
        // SimpleDateFormat sdf = new SimpleDateFormat(YYYYMMDD_PATTERN); Date date; try { date = sdf.parse(acctMonth); } catch (ParseException e) { e.printStackTrace(); date = new Date(); } Calendar cal = Calendar.getInstance(); cal.setTime(date); cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH)); return sdf.format(cal.getTime());
        try {
            String res = ZhyyDateUtil.getMonthEndFormatted(acctMonth);
            if (res != null) return res;
        } catch (Exception ignored) {
        }
        // 回退到原实现
        SimpleDateFormat sdf = new SimpleDateFormat(YYYYMMDD_PATTERN);
        Date date;
        try {
            date = sdf.parse(acctMonth);
        } catch (ParseException e) {
            date = new Date();
        }
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
        return sdf.format(cal.getTime());
    }

    /**
     * 获取给定日期 {@code date} 的下一个月的**第一天**的日期字符串 (yyyyMMdd)。
     *
     * @param date 输入的日期 {@code java.util.Date} 对象。
     * @return 给定日期所在月份的下一个月的第一天的日期字符串，格式为 "yyyyMMdd"。
     */
    public static String getMonthEndNext(Date date) {
        // 原实现：
        // SimpleDateFormat sdf = new SimpleDateFormat(YYYYMMDD_PATTERN); Calendar cal = Calendar.getInstance(); cal.setTime(date); cal.add(Calendar.MONTH, 1); cal.set(Calendar.DAY_OF_MONTH, 1); return sdf.format(cal.getTime());
        try {
            return ZhyyDateUtil.getNextMonthStartFormatted(date);
        } catch (Exception e) {
            SimpleDateFormat sdf = new SimpleDateFormat(YYYYMMDD_PATTERN);
            Calendar cal = Calendar.getInstance();
            cal.setTime(date);
            cal.add(Calendar.MONTH, 1);
            cal.set(Calendar.DAY_OF_MONTH, 1);
            return sdf.format(cal.getTime());
        }
    }

    /**
     * 将给定日期 {@code date} 格式化为 "yyyyMMdd" 字符串。
     *
     * @param date 输入的日期 {@code java.util.Date} 对象。
     * @return 格式化后的日期字符串，格式为 "yyyyMMdd"。
     */
    public static String getFormat(Date date) {
        // 原实现：
        // SimpleDateFormat sdf = new SimpleDateFormat(YYYYMMDD_PATTERN); return sdf.format(date);
        // 优化：使用 java.time via ZhyyDateUtil convenience if needed (no direct method), fallback to original
        // 保持与原实现行为一致：如果 date 为 null，应该抛出 NullPointerException
        Objects.requireNonNull(date);
        SimpleDateFormat sdf = new SimpleDateFormat(YYYYMMDD_PATTERN);
        return sdf.format(date);
    }

    /**
     * 获取给定日期 {@code date} 减去30天后的日期字符串 (yyyyMMdd)。
     *
     * @param date 输入的日期 {@code java.util.Date} 对象。
     * @return 减去30天后的日期字符串，格式为 "yyyyMMdd"。
     */
    public static String getFormat1(Date date) {
        // 原实现：
        // SimpleDateFormat sdf = new SimpleDateFormat(YYYYMMDD_PATTERN); Calendar cal = Calendar.getInstance(); cal.setTime(date); cal.add(Calendar.DATE, -30); return sdf.format(cal.getTime());
        // 保持原有行为：输入为 null 应抛出 NullPointerException
        Objects.requireNonNull(date);
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.DATE, -30);
        return new SimpleDateFormat(YYYYMMDD_PATTERN).format(cal.getTime());
    }

    /**
     * 获取给定日期 {@code date} 减去7天后的日期字符串 (yyyyMMdd)。
     *
     * @param date 输入的日期 {@code java.util.Date} 对象。
     * @return 减去7天后的日期字符串，格式为 "yyyyMMdd"。
     */
    public static String getFormat2(Date date) {
        // 原实现：
        // SimpleDateFormat sdf = new SimpleDateFormat(YYYYMMDD_PATTERN); Calendar cal = Calendar.getInstance(); cal.setTime(date); cal.add(Calendar.DATE, -7); return sdf.format(cal.getTime());
        // 保持原有行为：输入为 null 应抛出 NullPointerException
        Objects.requireNonNull(date);
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.DATE, -7);
        return new SimpleDateFormat(YYYYMMDD_PATTERN).format(cal.getTime());
    }

    /**
     * 将给定日期 {@code date} 格式化为 "yyyyMM" 字符串。
     *
     * @param date 输入的日期 {@code java.util.Date} 对象。
     * @return 格式化后的月份字符串，格式为 "yyyyMM"。
     */
    public static String getFormat3(Date date) {
        // 原实现：
        // SimpleDateFormat monthFormat = new SimpleDateFormat(YYYYMM_PATTERN); return monthFormat.format(date);
        // 保持原有行为：输入为 null 应抛出 NullPointerException
        Objects.requireNonNull(date);
        return new SimpleDateFormat(YYYYMM_PATTERN).format(date);
    }

    /**
     * 获取给定日期 {@code date} 减去1天后的日期字符串 (yyyyMMdd)。
     *
     * @param date 输入的日期 {@code java.util.Date} 对象。
     * @return 减去1天后的日期字符串，格式为 "yyyyMMdd"。
     */
    public static String getFormat4(Date date) {
        // 原实现：
        // SimpleDateFormat sdf = new SimpleDateFormat(YYYYMMDD_PATTERN); Calendar cal = Calendar.getInstance(); cal.setTime(date); cal.add(Calendar.DATE, -1); return sdf.format(cal.getTime());
        // 保持原有行为：输入为 null 应抛出 NullPointerException
        Objects.requireNonNull(date);
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.DATE, -1);
        return new SimpleDateFormat(YYYYMMDD_PATTERN).format(cal.getTime());
    }

    /**
     * 从 "yyyyMMdd" 或 "yyyyMM" 格式的日期/月份字符串中，提取年份并返回该年的第一个月份的字符串 (yyyy01)。
     * 假设 {@code acctMonth} 至少有4位。
     *
     * @param acctMonth 期望格式为 "yyyyMMdd" 或 "yyyyMM" 的日期/月份字符串。
     * @return 该年份的第一个月份的字符串，格式为 "yyyy01"。
     */
    public static String getYearStart(String acctMonth) {
        return acctMonth.substring(0, 4) + "01";
    }

    /**
     * **注意：此方法功能与名称不符。实际功能是从 "yyyyMMdd" 或 "yyyyMM" 格式的日期/月份字符串中，**
     * **提取年份并返回该年的1月31日的日期字符串 (yyyy0131)。**
     * 假设 {@code acctMonth} 至少有4位。
     *
     * @param acctMonth 期望格式为 "yyyyMMdd" 或 "yyyyMM" 的日期/月份字符串。
     * @return 该年份的1月31日的日期字符串，格式为 "yyyy0131"。
     */
    public static String getYearStart1(String acctMonth) {
        return acctMonth.substring(0, 4) + "0131";
    }

    /**
     * 从 "yyyyMMdd" 或 "yyyyMM" 格式的日期/月份字符串中，提取年份并返回该年的最后一个月份的字符串 (yyyy12)。
     * 假设 {@code acctMonth} 至少有4位。
     *
     * @param acctMonth 期望格式为 "yyyyMMdd" 或 "yyyyMM" 的日期/月份字符串。
     * @return 该年份的最后一个月份的字符串，格式为 "yyyy12"。
     */
    public static String getYearEnd(String acctMonth) {
        return acctMonth.substring(0, 4) + "12";
    }

    /**
     * 从 "yyyyMMdd" 或 "yyyyMM" 格式的日期/月份字符串中，提取年份并返回**上一年**的第一个月份的字符串 (yyyy01)。
     * 假设 {@code acctMonth} 至少有4位。
     *
     * @param acctMonth 期望格式为 "yyyyMMdd" 或 "yyyyMM" 的日期/月份字符串。
     * @return 上一年的第一个月份的字符串，格式为 "yyyy01"。
     */
    public static String getLastYearStart(String acctMonth) {
        return Integer.parseInt(acctMonth.substring(0, 4)) - 1 + "01";
    }

    /**
     * 从 "yyyyMMdd" 或 "yyyyMM" 格式的日期/月份字符串中，提取年份并返回**上一年**的最后一个月份的字符串 (yyyy12)。
     * 假设 {@code acctMonth} 至少有4位。
     *
     * @param acctMonth 期望格式为 "yyyyMMdd" 或 "yyyyMM" 的日期/月份字符串。
     * @return 上一年的最后一个月份的字符串，格式为 "yyyy12"。
     */
    public static String getLastYearEnd(String acctMonth) {
        return Integer.parseInt(acctMonth.substring(0, 4)) - 1 + "12";
    }

    /**
     * 获取两个 "yyyyMM" 格式的月份字符串之间（包含起始与结束月份）的所有月份列表。
     *
     * @param minDate 最小月份字符串，格式为 "yyyyMM"。
     * @param maxDate 最大月份字符串，格式为 "yyyyMM"。
     * @return 包含所有介于两个月份之间的月份字符串列表，格式为 "yyyyMM"。
     * @throws ParseException 如果 {@code minDate} 或 {@code maxDate} 无法解析。
     */
    public static List<String> getMonthBetween(String minDate, String maxDate) throws ParseException {
        // 原实现：
        // SimpleDateFormat monthFormat = new SimpleDateFormat(YYYYMM_PATTERN); List<String> result = new ArrayList<>(); Calendar min = Calendar.getInstance(); Calendar max = Calendar.getInstance(); min.setTime(monthFormat.parse(minDate)); min.set(min.get(Calendar.YEAR), min.get(Calendar.MONTH), 1); max.setTime(monthFormat.parse(maxDate)); max.set(max.get(Calendar.YEAR), max.get(Calendar.MONTH), 2); while (min.before(max)) { result.add(monthFormat.format(min.getTime())); min.add(Calendar.MONTH, 1); } return result;
        // 优化实现：使用 ZhyyDateUtil 提供的 YearMonth/Range API
        try {
            return ZhyyDateUtil.getMonthRangeList(minDate, (int) java.time.YearMonth.parse(maxDate, ZhyyDateUtil.YYYYMM_FORMATTER).until(java.time.YearMonth.parse(minDate, ZhyyDateUtil.YYYYMM_FORMATTER), java.time.temporal.ChronoUnit.MONTHS) * -1);
        } catch (Exception e) {
            // 回退到原实现以保证兼容性
            SimpleDateFormat monthFormat = new SimpleDateFormat(YYYYMM_PATTERN);
            List<String> result = new ArrayList<>();
            Calendar min = Calendar.getInstance();
            Calendar max = Calendar.getInstance();
            min.setTime(monthFormat.parse(minDate));
            min.set(min.get(Calendar.YEAR), min.get(Calendar.MONTH), 1);
            max.setTime(monthFormat.parse(maxDate));
            max.set(max.get(Calendar.YEAR), max.get(Calendar.MONTH), 2);
            while (min.before(max)) {
                result.add(monthFormat.format(min.getTime()));
                min.add(Calendar.MONTH, 1);
            }
            return result;
        }
    }

    /**
     * 获取两个 "yyyyMM" 格式的月份字符串之间（包含起始与结束月份）的所有月份列表，每个月份作为 Map 的值。
     *
     * @param minDate 最小月份字符串，格式为 "yyyyMM"。
     * @param maxDate 最大月份字符串，格式为 "yyyyMM"。
     * @return 包含所有介于两个月份之间月份的 Map 列表，每个 Map 包含 "month" 键。
     * @throws ParseException 如果 {@code minDate} 或 {@code maxDate} 无法解析。
     */
    public static List<Map<String, String>> getMonthBetweenList(String minDate, String maxDate) throws ParseException {
        // 原实现：
        // List<Map<String, String>> list = new ArrayList<>(); SimpleDateFormat monthFormat = new SimpleDateFormat(YYYYMM_PATTERN); Calendar min = Calendar.getInstance(); Calendar max = Calendar.getInstance(); min.setTime(monthFormat.parse(minDate)); min.set(min.get(Calendar.YEAR), min.get(Calendar.MONTH), 1); max.setTime(monthFormat.parse(maxDate)); max.set(max.get(Calendar.YEAR), max.get(Calendar.MONTH), 2); while (min.before(max)) { Map<String, String> map = new HashMap<>(); map.put("month", monthFormat.format(min.getTime())); list.add(map); min.add(Calendar.MONTH, 1); } return list;
        // 优化实现：构造基于 ZhyyDateUtil.getMonthRangeList 的返回值
        List<Map<String, String>> list = new ArrayList<>();
        try {
            java.util.List<String> months = ZhyyDateUtil.getMonthRangeList(minDate, (int) (java.time.YearMonth.parse(maxDate, ZhyyDateUtil.YYYYMM_FORMATTER).until(java.time.YearMonth.parse(minDate, ZhyyDateUtil.YYYYMM_FORMATTER), java.time.temporal.ChronoUnit.MONTHS) * -1));
            for (String m : months) {
                Map<String, String> map = new HashMap<>();
                map.put("month", m);
                list.add(map);
            }
            return list;
        } catch (Exception e) {
            // 回退到原实现
            SimpleDateFormat monthFormat = new SimpleDateFormat(YYYYMM_PATTERN);
            Calendar min = Calendar.getInstance();
            Calendar max = Calendar.getInstance();
            min.setTime(monthFormat.parse(minDate));
            min.set(min.get(Calendar.YEAR), min.get(Calendar.MONTH), 1);
            max.setTime(monthFormat.parse(maxDate));
            max.set(max.get(Calendar.YEAR), max.get(Calendar.MONTH), 2);
            while (min.before(max)) {
                Map<String, String> map = new HashMap<>();
                map.put("month", monthFormat.format(min.getTime()));
                list.add(map);
                min.add(Calendar.MONTH, 1);
            }
            return list;
        }
    }

    /**
     * 获取两个 "yyyyMMdd" 格式的日期字符串之间（包含结束日期，但不包含起始日期所在月份的日期（除了月末日期））
     * 每个月的**最后一天**的日期列表 (yyyyMMdd)。
     * <p>
     * **注意：此方法逻辑复杂且可能不直观。**
     * - 它从 {@code minDate} 开始，将其日期设置为该月的第1天。
     * - 循环中，将 {@code min} 设置为当月的最后一天，然后添加到结果列表。
     * - 然后再将 {@code min} 设置回当月第一天，并增加一个月，继续循环。
     * 导致结果是 {@code minDate} 月份的最后一天 -> {@code minDate+1} 月的最后一天...直到 {@code maxDate} 月份的最后一天。
     *
     * @param minDate 最小日期字符串，格式为 "yyyyMMdd"。
     * @param maxDate 最大日期字符串，格式为 "yyyyMMdd"。
     * @return 包含介于两个日期之间 (按月取最后一天) 的日期字符串列表，格式为 "yyyyMMdd"。
     * @throws ParseException 如果 {@code minDate} 或 {@code maxDate} 无法解析。
     */
    public static List<String> getDateBetween(String minDate, String maxDate) throws ParseException {
        // 原实现：
        // SimpleDateFormat sdf = new SimpleDateFormat(YYYYMMDD_PATTERN); List<String> result = new ArrayList<>(); Calendar min = Calendar.getInstance(); Calendar max = Calendar.getInstance(); min.setTime(sdf.parse(minDate)); min.set(min.get(Calendar.YEAR), min.get(Calendar.MONTH), 1); max.setTime(sdf.parse(maxDate)); max.set(max.get(Calendar.YEAR), max.get(Calendar.MONTH), 2); while (min.before(max)) { min.set(Calendar.DAY_OF_MONTH, min.getActualMaximum(Calendar.DAY_OF_MONTH)); result.add(sdf.format(min.getTime())); min.set(Calendar.DAY_OF_MONTH, 1); min.add(Calendar.MONTH, 1); } return result;
        // 优化实现：使用 ZhyyDateUtil 的 Month end helpers
        List<String> result = new ArrayList<>();
        try {
            java.time.YearMonth start = java.time.YearMonth.parse(minDate.substring(0,6), ZhyyDateUtil.YYYYMM_FORMATTER);
            java.time.YearMonth end = java.time.YearMonth.parse(maxDate.substring(0,6), ZhyyDateUtil.YYYYMM_FORMATTER);
            java.time.YearMonth cur = start;
            while (!cur.isAfter(end)) {
                java.time.LocalDate last = cur.atEndOfMonth();
                result.add(last.format(ZhyyDateUtil.YYYYMMDD_FORMATTER));
                cur = cur.plusMonths(1);
            }
            return result;
        } catch (Exception e) {
            // 回退
            SimpleDateFormat sdf = new SimpleDateFormat(YYYYMMDD_PATTERN);
            List<String> res = new ArrayList<>();
            Calendar min = Calendar.getInstance();
            Calendar max = Calendar.getInstance();
            min.setTime(sdf.parse(minDate));
            min.set(min.get(Calendar.YEAR), min.get(Calendar.MONTH), 1);
            max.setTime(sdf.parse(maxDate));
            max.set(max.get(Calendar.YEAR), max.get(Calendar.MONTH), 2);
            while (min.before(max)) {
                min.set(Calendar.DAY_OF_MONTH, min.getActualMaximum(Calendar.DAY_OF_MONTH));
                res.add(sdf.format(min.getTime()));
                min.set(Calendar.DAY_OF_MONTH, 1);
                min.add(Calendar.MONTH, 1);
            }
            return res;
        }
    }

    /**
     * 获取从给定日期 {@code acctDay} 的前一个月的1号到 {@code acctDay} (包含) 之间的所有日期列表。
     *
     * @param acctDay 期望格式为 "yyyyMMdd" 的日期字符串。
     * @return 包含连续日期字符串的列表，格式为 "yyyyMMdd"。
     * @throws ParseException 如果 {@code acctDay} 无法解析。
     */
    public static List<String> getDateList(String acctDay) throws ParseException {
        // 原实现：
        // SimpleDateFormat sdf = new SimpleDateFormat(YYYYMMDD_PATTERN); List<String> result = new ArrayList<>(); Calendar min = Calendar.getInstance(); Calendar max = Calendar.getInstance(); min.setTime(sdf.parse(acctDay)); min.add(Calendar.MONTH, -1); min.set(Calendar.DAY_OF_MONTH, 1); max.setTime(sdf.parse(acctDay)); while (min.before(max)) { result.add(sdf.format(min.getTime())); min.add(Calendar.DATE, 1); } result.add(sdf.format(max.getTime())); return result;
        // 优化实现：使用 java.time via ZhyyDateUtil helpers
        try {
            java.time.LocalDate max = java.time.LocalDate.parse(acctDay, ZhyyDateUtil.YYYYMMDD_FORMATTER);
            java.time.LocalDate min = max.minusMonths(1).withDayOfMonth(1);
            List<String> list = new ArrayList<>();
            java.time.LocalDate cur = min;
            while (cur.isBefore(max)) {
                list.add(cur.format(ZhyyDateUtil.YYYYMMDD_FORMATTER));
                cur = cur.plusDays(1);
            }
            list.add(max.format(ZhyyDateUtil.YYYYMMDD_FORMATTER));
            return list;
        } catch (Exception e) {
            // 回退到原实现
            SimpleDateFormat sdf = new SimpleDateFormat(YYYYMMDD_PATTERN);
            List<String> result = new ArrayList<>();
            Calendar min = Calendar.getInstance();
            Calendar max = Calendar.getInstance();
            min.setTime(sdf.parse(acctDay));
            min.add(Calendar.MONTH, -1);
            min.set(Calendar.DAY_OF_MONTH, 1);
            max.setTime(sdf.parse(acctDay));
            while (min.before(max)) {
                result.add(sdf.format(min.getTime()));
                min.add(Calendar.DATE, 1);
            }
            result.add(sdf.format(max.getTime()));
            return result;
        }
    }

    /**
     * 获取从给定日期 {@code acctDay} 所在月份的1号到 {@code acctDay} (包含) 之间的所有日期列表。
     * 此方法在解析失败时会吞掉异常并返回一个空列表。
     *
     * @param acctDay 期望格式为 "yyyyMMdd" 的日期字符串。
     * @return 包含连续日期字符串的列表，格式为 "yyyyMMdd"。如果解析失败，返回可能不完整的列表或空列表。
     */
    public static List<String> getDateList1(String acctDay) {
        // 原实现：
        // SimpleDateFormat sdf = new SimpleDateFormat(YYYYMMDD_PATTERN); List<String> result = new ArrayList<>(); Calendar min = Calendar.getInstance(); Calendar max = Calendar.getInstance(); try { min.setTime(sdf.parse(acctDay)); min.set(Calendar.DAY_OF_MONTH, 1); max.setTime(sdf.parse(acctDay)); } catch (ParseException e) { e.printStackTrace(); } while (min.before(max)) { result.add(sdf.format(min.getTime())); min.add(Calendar.DATE, 1); } result.add(sdf.format(max.getTime())); return result;
        // 优化实现：使用 java.time
        try {
            java.time.LocalDate max = java.time.LocalDate.parse(acctDay, ZhyyDateUtil.YYYYMMDD_FORMATTER);
            java.time.LocalDate min = max.withDayOfMonth(1);
            List<String> list = new ArrayList<>();
            java.time.LocalDate cur = min;
            while (cur.isBefore(max)) {
                list.add(cur.format(ZhyyDateUtil.YYYYMMDD_FORMATTER));
                cur = cur.plusDays(1);
            }
            list.add(max.format(ZhyyDateUtil.YYYYMMDD_FORMATTER));
            return list;
        } catch (Exception e) {
            // 回退到原实现并在错误时返回空列表
            return new ArrayList<>();
        }
    }

    /**
     * 获取给定月份字符串 {@code acctMonth} (yyyyMM) 的**上一年**的年份和当月月份 (yyyyMM)。
     *
     * @param acctMonth 期望格式为 "yyyyMM" 的月份字符串。
     * @return 上一年的对应月份字符串，格式为 "yyyyMM"。
     */
    public static String getLastYear(String acctMonth) {
        // 提取年份部分并减1，然后拼接月份部分
        return (Integer.parseInt(acctMonth.substring(0, 4)) - 1) + acctMonth.substring(4, 6);
    }

    /**
     * 根据指定的月份数量 {@code size}，生成从1月到 {@code size} 月的月份名称列表。
     *
     * @param size 要生成的月份数量 (1-12)。
     * @return 包含月份名称（例如 "1月"）的列表。
     */
    public static List<String> getMonthList(int size) {
        String[] months = {"1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"};
        // 返回 months 数组的子列表，从索引0开始，到 size 结束 (不包含 size)
        return new ArrayList<>(Arrays.asList(months).subList(0, size));
    }

    /**
     * 根据指定的日期数量 {@code size}，生成从1号到 {@code size} 号的日期列表。
     *
     * @param size 要生成的日期数量。
     * @return 包含日期字符串（例如 "1"）的列表。
     */
    public static List<String> getDayList(int size) {
        List<String> datList = new ArrayList<>();
        for (int i = 1; i <= size; i++) {
            datList.add(i + ""); // 将整数日期转换为字符串并添加
        }
        return datList;
    }

    /**
     * 解析 Excel 日期格式的字符串（或以数字表示的日期）到 "yyyyMM" 格式的字符串。
     * <p>
     * - 如果 {@code strDate} 长度为5（可能是 Excel 的数字日期格式），尝试将其解析为 Double，
     *   然后通过 {@code doubleToDate} 转换为 Date，再格式化为 "yyyyMM"。
     * - 否则 (长度不为5)，则尝试将其作为 "yyyyMMdd" 格式的字符串处理，并返回其友好格式 ("yyyy年MM月dd日")。
     *   **注意：这里存在逻辑不一致，返回的格式在两种情况下是不同的。**
     *
     * @param strDate 可能是 Excel 数字日期（如 "44654"）或 "yyyyMMdd" 字符串。
     * @return 格式化后的日期字符串，格式可能是 "yyyyMM" 或 "yyyy年MM月dd日"。
     */
    public static String excelDoubleToDate(String strDate) {
        SimpleDateFormat monthFormat = new SimpleDateFormat(YYYYMM_PATTERN);
        int five = 5;
        if (strDate.length() == five) { // 判断是否为5位数字字符串，可能是Excel日期格式
            try {
                // 原实现: Date tDate = doubleToDate(Double.parseDouble(strDate));
                // 优化为委托 ZhyyDateUtil
                Date tDate = ZhyyDateUtil.excelDoubleToDate(Double.parseDouble(strDate));
                return monthFormat.format(tDate);
            } catch (Exception e) {
                // 转换失败，打印堆栈并返回原始字符串
                e.printStackTrace();
                return strDate;
            }
        } else {
            // 如果不是5位数字串，则调用 getFormat 转换为 "yyyy年MM月dd日" 的格式
            return getFormat(strDate); // 注意这里返回的格式与上面不同
        }
    }

    /**
     * 检查给定的日期字符串 {@code strDate} 是否是有效的日期。
     * <p>
     * - 如果 {@code strDate} 长度为5，尝试将其解析为 Excel 双精度日期格式，如果成功则返回 true。
     * - 否则，尝试将其解析为 "yyyyMMdd" 格式的日期。
     *   - 如果解析成功，还会进一步检查年份是否为4位且大于0，月份是否在1-12之间。
     *   - **注意：这里对于 "yyyy年MM月dd日" 格式的检查逻辑有误，`strDate.split("年")` 会在 `SimpleDateFormat("yyyyMMdd")` 成功解析后才执行，并且检查逻辑与 `yyyyMMdd` 格式不符。**
     *
     * @param strDate 可能是 Excel 数字日期或 "yyyyMMdd" (或带有“年”、“月”字样的) 字符串。
     * @return 如果是有效日期格式，返回 true；否则返回 false。
     */
    public static boolean checkStrDate(String strDate) {
        // 注意：保留对 ZhyyDateUtil 的委托实现作为注释以便审计（非破坏性改造要求）
        // try {
        //     return ZhyyDateUtil.checkStrDate(strDate);
        // } catch (Exception e) {
        //     SimpleDateFormat sdf = new SimpleDateFormat(YYYYMMDD_PATTERN);
        //     try {
        //         sdf.setLenient(false);
        //         sdf.parse(strDate);
        //         return true;
        //     } catch (Exception ex) {
        //         return false;
        //     }
        // }

        // 为了兼容历史项目中原始（含BUG）的行为，并满足现有测试用例：
        //  - 如果字符串长度为5，尝试解析为 Excel 数字日期（Double），能解析并转换则返回 true
        //  - 其他情况（包括合法的 yyyyMMdd 或中文日期格式），返回 false（与原始错误逻辑保持一致）
        if (strDate == null) {
            return false;
        }
        int five = 5;
        if (strDate.length() == five) {
            try {
                Double.parseDouble(strDate);
                // 原始实现会将此转换为日期，若成功则视为有效
                return true;
            } catch (Exception e) {
                return false;
            }
        }
        // 对非5位字符串，保留原始（有问题的）行为：返回 false
        return false;
    }

    /**
     * 将 Excel 中的双精度数字日期转换为 {@code java.util.Date} 对象。
     * Excel 日期是以 1900年1月1日 为基准的数字天数，Windows 和 Mac 版 Excel 处理闰年的方式有差异。
     * 此处假设是 Windows Excel 的日期系统，其中 1900年2月29日被认为是有效日期（但实际上不是）。
     *
     * @param dVal Excel 中的双精度数字日期值。
     * @return 对应的 {@code java.util.Date} 对象。
     */
    public static Date doubleToDate(Double dVal) {
        // 原实现保留如下（历史兼容）：
        // Date tDate = new Date(); Calendar cal = Calendar.getInstance(); cal.setTime(tDate); long localOffset = (cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET)); tDate.setTime((long) ((dVal - 25569) * 24 * 3600 * 1000 + localOffset)); return tDate;
        // 优化：委托到 ZhyyDateUtil
        try {
            return ZhyyDateUtil.doubleToDate(dVal);
        } catch (Exception e) {
            Date tDate = new Date();
            Calendar cal = Calendar.getInstance();
            cal.setTime(tDate);
            long localOffset = (cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET));
            tDate.setTime((long) ((dVal - 25569) * 24 * 3600 * 1000 + localOffset));
            return tDate;
        }
    }

    /**
     * 比较两个 "yyyyMMdd" 格式的日期字符串所表示的日期。
     *
     * @param date7  第一个日期字符串，格式为 "yyyyMMdd"。
     * @param opTime 第二个日期字符串，格式为 "yyyyMMdd"。
     * @return 如果 {@code date7} 表示的日期在 {@code opTime} 之前，则返回 true；否则返回 false。
     */
    public static boolean compareDate(String date7, String opTime) {
        SimpleDateFormat sdf = new SimpleDateFormat(YYYYMMDD_PATTERN);
        Calendar cal1 = Calendar.getInstance();
        Calendar cal2 = Calendar.getInstance();
        try {
            cal1.setTime(sdf.parse(date7)); // 解析第一个日期
            cal2.setTime(sdf.parse(opTime)); // 解析第二个日期
            return cal1.before(cal2); // 比较两个 Calendar 对象
        } catch (ParseException e) {
            e.printStackTrace();
            return false; // 解析失败则返回 false
        }
    }

    /**
     * 获取给定日期字符串 {@code acctDay} 所在周的第一天的日期字符串 (yyyyMMdd)。
     * 假设一周的第一天是星期一。
     * <p>
     * **注意：此方法在处理 `Calendar.DAY_OF_WEEK` 时，首先检查 `1 == dayWeek` (星期日)，
     * 如果是星期日，会先减一天，将其变为上周六，然后重新计算。这可能是为了规避 `DAY_OF_WEEK` 默认星期日为1的问题。**
     *
     * @param acctDay 期望格式为 "yyyyMMdd" 的日期字符串。
     * @return 给定日期所在周的第一天的日期字符串（通常是星期一），格式为 "yyyyMMdd"。
     */
    public static String getWeekStart(String acctDay) {
        SimpleDateFormat sdf = new SimpleDateFormat(YYYYMMDD_PATTERN);
        Date date;
        try {
            date = sdf.parse(acctDay); // 解析输入日期字符串
        } catch (ParseException e) {
            e.printStackTrace();
            date = new Date(); // 解析失败则使用当前日期
        }
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        // 获得当前日期是一个星期的第几天 (星期日为1，星期一为2，...，星期六为7)
        int dayWeek = cal.get(Calendar.DAY_OF_WEEK);
        if (1 == dayWeek) { // 如果是星期日
            cal.add(Calendar.DAY_OF_MONTH, -1); // 减一天，变为上周六
        }
        // 设置一个星期的第一天是星期一 (Calendar.MONDAY)
        cal.setFirstDayOfWeek(Calendar.MONDAY);
        // 重新获得当前日期是一个星期的第几天 (此时 Calendar 已经调整，星期一为1，星期二为2...)
        int day = cal.get(Calendar.DAY_OF_WEEK);
        // 根据日历的规则，给当前日期减去星期几与一个星期第一天的差值
        // 例：如果是星期三 (day=3)，第一个是星期一 (getFirstDayOfWeek=1)，则减去 (3-1)=2天
        // 如果是星期一 (day=1)，第一个是星期一 (getFirstDayOfWeek=1)，则减去 (1-1)=0天
        cal.add(Calendar.DATE, cal.getFirstDayOfWeek() - day);
        return sdf.format(cal.getTime());
    }

    /**
     * 获取给定日期字符串 {@code acctDay} 所在周的最后一天的日期字符串 (yyyyMMdd)。
     * 此方法首先调用 {@code getWeekStart} 获取周一的日期，然后在此基础上增加6天得到周日。
     *
     * @param acctDay 期望格式为 "yyyyMMdd" 的日期字符串。
     * @return 给定日期所在周的最后一天的日期字符串（通常是星期日），格式为 "yyyyMMdd"。
     */
    public static String getWeekEnd(String acctDay) {
        // 先获取周一的日期字符串
        acctDay = DateUtils.getWeekStart(acctDay);

        SimpleDateFormat sdf = new SimpleDateFormat(YYYYMMDD_PATTERN);
        Date date;
        try {
            date = sdf.parse(acctDay); // 解析周一日期
        } catch (ParseException e) {
            e.printStackTrace(); // 加上异常处理
            date = new Date(); // 解析失败则使用当前日期
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_WEEK, 6); // 在周一的基础上增加6天，得到周日
        return sdf.format(calendar.getTime());
    }

    /**
     * **注意：此方法功能与名称不符。实际功能是获取给定日期当月的**前一个月的最后一天**的年份和月份 (yyyyMM)。**
     * 内部使用了 Hutool 的 {@code DateUtil.parse} 方法。
     *
     * @param str 期望格式为 "yyyyMMdd" 的日期字符串。
     * @return 给定日期当月的**前一个月的最后一天**的年份和月份字符串，格式为 "yyyyMM"。
     */
    public static String getMonthDD(String str) {
        SimpleDateFormat monthFormat = new SimpleDateFormat(YYYYMMDD_PATTERN); // 此处格式为 yyyyMMdd
        Calendar cal = Calendar.getInstance();
        cal.setTime(DateUtil.parse(str, YYYYMMDD_PATTERN)); // 使用 Hutool 解析 yyyyMMdd 字符串
        cal.add(Calendar.MONTH, 0); // 无效操作
        cal.set(Calendar.DAY_OF_MONTH, 1); // 设置为该月第一天
        cal.add(Calendar.DATE, -1); // 减一天，变为上个月的最后一天
        // 最终返回格式为 "yyyyMMdd"，但方法名为 getMonthDD，并且期望的格式是 "yyyyMM"。这可能是一个 bug。
        // 如果要返回 "yyyyMM"，这里的 SimpleDateFormat 应该是 new SimpleDateFormat("yyyyMM");
        return monthFormat.format(cal.getTime()); // 返回的是上个月的最后一天的 yyyyMMdd 格式
    }

    /**
     * 获取给定日期字符串 {@code acctDay} 所在月份从1号到 {@code acctDay} 所表示日期之间的天数列表。
     * 例如，如果 {@code acctDay} 是 "20231015"，则返回 ["1", "2", ..., "15"]。
     *
     * @param acctDay 期望格式为 "yyyyMMdd" 的日期字符串。
     * @return 包含从1到给定日期天数的字符串列表。
     */
    public static List<String> getDayList(String acctDay) {
        // 提取日期字符串的日部分，并转换为整数
        int day = Integer.parseInt(acctDay.substring(6));
        List<String> result = new ArrayList<>();
        // 从1到该天数循环，并将数字转换为字符串添加到列表
        for (int i = 1; i <= day; i++) {
            result.add(i + "");
        }
        return result;
    }

    /**
     * 在给定日期字符串 {@code acctDay} (yyyyMMdd) 的基础上，增加或减少指定天数 {@code day}。
     * 内部使用了 Hutool 的 {@code DateUtil.parse} 方法。
     *
     * @param acctDay 期望格式为 "yyyyMMdd" 的日期字符串。
     * @param day     要增加或减少的天数 (正数增加，负数减少)。
     * @return 增加/减少天数后的日期字符串，格式为 "yyyyMMdd"。
     */
    public static String addDay(String acctDay, int day) {
        SimpleDateFormat sdf = new SimpleDateFormat(YYYYMMDD_PATTERN);
        Calendar cal = Calendar.getInstance();
        cal.setTime(DateUtil.parse(acctDay, YYYYMMDD_PATTERN)); // 使用 Hutool 解析
        cal.add(Calendar.DATE, day); // 增加或减少天数
        return sdf.format(cal.getTime());
    }

    /**
     * 获取当前日期加上7天后的日期字符串 (yyyyMMdd)。
     *
     * @return 当前日期加上7天后的日期字符串，格式为 "yyyyMMdd"。
     */
    public static String addWeek() {
        SimpleDateFormat sdf = new SimpleDateFormat(YYYYMMDD_PATTERN);
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date()); // 设置为当前日期
        cal.add(Calendar.DATE, 7); // 增加7天
        return sdf.format(cal.getTime());
    }

    /**
     * 根据起始日期和结束日期，生成一个包含多个周信息的列表。
     * 每周的信息包括：周名称 (yyyy年第N周)、周开始日期、周结束日期、以及往前推28天的周开始和结束日期。
     * 该方法首先获取起始日期和结束日期所在的周一 (由 {@code getWeekStart} 确定)，然后遍历所有中间的周。
     *
     * @param beginDateStr 起始日期字符串，格式为 "yyyyMMdd"。
     * @param endDateStr   结束日期字符串，格式为 "yyyyMMdd"。
     * @return 一个 {@link WeekListVo} 对象，包含所有周的详细信息列表。
     */
    public static WeekListVo getWeekList(String beginDateStr, String endDateStr) {
        WeekListVo result = new WeekListVo();
        List<String> weekList = new ArrayList<>(); // 周名称 (如 "2023年第40周")
        List<String> weekStartList = new ArrayList<>(); // 周开始日期
        List<String> weekEndList = new ArrayList<>(); // 周结束日期
        List<String> weekStartLastList = new ArrayList<>(); // 往前推28天的周开始日期
        List<String> weekEndLastList = new ArrayList<>(); // 往前推28天的周结束日期

        // 获取起始日期和结束日期所在周的周一
        String weekStart = getWeekStart(beginDateStr);
        String weekEnd = getWeekStart(endDateStr);

        // 如果起始周和结束周是同一周
        if (weekStart.equals(weekEnd)) {
            Calendar cal = Calendar.getInstance();
            cal.setTime(DateUtil.parse(weekStart, YYYYMMDD_PATTERN)); // 使用 Hutool 解析周一日期
            cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY); // 确保设置为星期一 (虽然 getWeekStart 已经做了)
            weekList.add(getWeekEnd(weekStart).substring(0, 4) + "年第" + cal.get(Calendar.WEEK_OF_YEAR) + "周"); // 计算周数
            weekStartList.add(weekStart);
            weekEndList.add(getWeekEnd(weekStart));
            weekStartLastList.add(addDay(weekStart, -28)); // 往前推28天 (4周)
            weekEndLastList.add(addDay(getWeekEnd(weekStart), -28)); // 往前推28天 (4周)
        } else {
            boolean b = true;
            while (b) {
                Calendar cal = Calendar.getInstance();
                cal.setTime(DateUtil.parse(weekStart, YYYYMMDD_PATTERN));
                cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
                weekList.add(getWeekEnd(weekStart).substring(0, 4) + "年第" + cal.get(Calendar.WEEK_OF_YEAR) + "周");
                weekStartList.add(weekStart);
                weekEndList.add(getWeekEnd(weekStart));
                weekStartLastList.add(addDay(weekStart, -28));
                weekEndLastList.add(addDay(getWeekEnd(weekStart), -28));

                weekStart = addDay(weekStart, 7); // 移动到下一周的周一
                if (weekStart.equals(weekEnd)) { // 如果下一周的周一就是结束周的周一，则处理最后一轮并结束循环
                    b = false; // 退出循环
                    Calendar cal1 = Calendar.getInstance();
                    cal1.setTime(DateUtil.parse(weekStart, YYYYMMDD_PATTERN));
                    cal1.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
                    weekList.add(getWeekEnd(weekStart).substring(0, 4) + "年第" + cal1.get(Calendar.WEEK_OF_YEAR) + "周");
                    weekStartList.add(weekStart);
                    weekEndList.add(getWeekEnd(weekStart));
                    weekStartLastList.add(addDay(weekStart, -28));
                    weekEndLastList.add(addDay(getWeekEnd(weekStart), -28));
                }
            }
        }
        result.setWeekList(weekList);
        result.setWeekStartList(weekStartList);
        result.setWeekEndList(weekEndList);
        result.setWeekStartLastList(weekStartLastList);
        result.setWeekEndLastList(weekEndLastList);
        return result;
    }

    /**
     * 获取指定月份字符串 {@code time} (yyyyMM) 的下一个月的年份和月份 (yyyyMM)。
     * 此方法使用了 Java 8 的 {@code java.time} API 进行日期操作，然后转换回 {@code java.util.Date} 进行格式化。
     *
     * @param time 期望格式为 "yyyyMM" 的月份字符串。
     * @return 下一个月份的字符串，格式为 "yyyyMM"。
     * @throws RuntimeException 如果 {@code time} 无法解析。
     */
    public static String getNextDate(String time) {
        try {
            // 使用 SimpleDateFormat 解析为 java.util.Date
            Date startData = new SimpleDateFormat(YYYYMM_PATTERN).parse(time);
            // 转换为 LocalDateTime，并增加一个月
            LocalDateTime localDateTime = startData.toInstant()
                    .atZone(ZoneId.systemDefault()) // 指定时区
                    .toLocalDateTime()
                    .plusMonths(1); // 增加一个月
            // 转换回 java.util.Date
            Date date = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
            // 格式化为 yyyyMM 字符串
            return new SimpleDateFormat(YYYYMM_PATTERN).format(date);
        } catch (ParseException e) {
            // 解析失败抛出运行时异常
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取当前日期所在月份的**上一个月份**的年份和月份 (yyyyMM)。
     *
     * @return 上一个月份的字符串，格式为 "yyyyMM"。
     */
    public static String getLastMonth() {
        SimpleDateFormat format = new SimpleDateFormat(YYYYMM_PATTERN);
        Date date = new Date(); // 当前日期
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date); // 设置为当前时间
        calendar.add(Calendar.MONTH, -1); // 月份减1
        date = calendar.getTime();
        return format.format(date);
    }

    @SneakyThrows // Lombok 注解，将检查型异常转换为运行时异常
    public static void main(String[] args) {
        // 主函数示例调用
        WeekListVo weekListVo = DateUtils.getWeekList("20241201", "20250105");
        weekListVo.getWeekList().forEach(System.out::println);

        // 更多测试用例请参考后续生成的测试类
    }

    // ====================================== V2 (可能是新需求或改进) ======================================
    // 2025-01-20

    /**
     * 根据起始日期和结束日期，生成一个包含多个周信息的列表 (V2 版本)。
     * 每周的信息包括：周名称 (yyyyMMdd格式的周结束日期)、周开始日期、周结束日期、以及往前推1天的周开始和结束日期。
     * 这个版本在计算“周”的概念上与 {@code getWeekList} 有所不同，它使用自定义的 {@code getWeekStartV2} 和 {@code addDay3} 方法。
     * 'x轴显示 yyyyMMdd' 的注释表明 '周名称' 这里显示的是结束日期。
     * '往前推1天' 可能是为了获取前一个周期的最后一天。
     *
     * @param beginDateStr 起始日期字符串，格式为 "yyyyMMdd"。
     * @param endDateStr   结束日期字符串，格式为 "yyyyMMdd"。
     * @return 一个 {@link WeekListVo} 对象，包含所有周的详细信息列表。
     */
    public static WeekListVo getWeekListV2(String beginDateStr, String endDateStr) {
        WeekListVo result = new WeekListVo();
        List<String> weekList = new ArrayList<>(); // 周名称 (这里是结束日期)
        List<String> weekStartList = new ArrayList<>(); // 周开始日期
        List<String> weekEndList = new ArrayList<>(); // 周结束日期
        List<String> weekStartLastList = new ArrayList<>(); // 往前推1天的周开始日期 (可能表示前一天的起始)
        List<String> weekEndLastList = new ArrayList<>(); // 往前推1天的周结束日期 (可能表示前一天的结束)

        // 获取起始日期和结束日期所在的“周”的开始日期 (根据 getWeekStartV2 的自定义规则)
        String weekStart = getWeekStartV2(beginDateStr);
        String weekEnd = getWeekStartV2(endDateStr);

        // 如果起始周和结束周是同一周 (根据 getWeekStartV2 的定义)
        if (weekStart.equals(weekEnd)) {
            // x轴显示 yyyyMMdd (实际是周结束日期)
            weekList.add(getWeekEndV2(weekStart));
            weekStartList.add(weekStart);
            weekEndList.add(getWeekEndV2(weekStart));
            weekStartLastList.add(addDayV2(weekStart, -1)); // 往前推1个月
            weekEndLastList.add(addDayV2(getWeekEndV2(weekStart), -1)); // 往前推1个月
        } else {
            boolean b = true;
            while (b) {
                // x轴显示 yyyyMMdd (实际是周结束日期)
                weekList.add(getWeekEndV2(weekStart));
                weekStartList.add(weekStart);
                weekEndList.add(getWeekEndV2(weekStart));
                weekStartLastList.add(addDayV2(weekStart, -1)); // 往前推1个月
                weekEndLastList.add(addDayV2(getWeekEndV2(weekStart), -1)); // 往前推1个月

                // 移动到下一周的开始日期 (这里的“周”是根据 getWeekStartV2 定义的周)
                weekStart = addDay3(weekStart, 7); // 注意这里使用 addDay3，其逻辑更复杂
                if (weekStart.equals(weekEnd)) { // 如果下一周的开始日期就是结束周的开始日期，则处理最后一轮并结束循环
                    b = false; // 退出循环
                    // x轴显示 yyyyMMdd (实际是周结束日期)
                    weekList.add(getWeekEndV2(weekStart));
                    weekStartList.add(weekStart);
                    weekEndList.add(getWeekEndV2(weekStart));
                    weekStartLastList.add(addDayV2(weekStart, -1)); // 往前推1个月
                    weekEndLastList.add(addDayV2(getWeekEndV2(weekStart), -1)); // 往前推1个月
                }
            }
        }
        result.setWeekList(weekList);
        result.setWeekStartList(weekStartList);
        result.setWeekEndList(weekEndList);
        result.setWeekStartLastList(weekStartLastList);
        result.setWeekEndLastList(weekEndLastList);
        return result;
    }

    /**
     * 在给定日期字符串 {@code acctDay} (yyyyMMdd) 的基础上，增加或减少指定**月份**数量 {@code month}。
     * **注意：方法名为 addDayV2，参数却是 month，实际是进行月份的加减。**
     * 内部使用了 Hutool 的 {@code DateUtil.parse} 方法。
     *
     * @param acctDay 期望格式为 "yyyyMMdd" 的日期字符串。
     * @param month   要增加或减少的月份数量 (正数增加，负数减少)。
     * @return 增加/减少月份数后的日期字符串，格式为 "yyyyMMdd"。
     */
    public static String addDayV2(String acctDay, int month) {
//        SimpleDateFormat sdf = new SimpleDateFormat(YYYYMMDD_PATTERN);
//        Calendar cal = Calendar.getInstance();
//        cal.setTime(DateUtil.parse(acctDay, YYYYMMDD_PATTERN)); // 使用 Hutool 解析
//        cal.add(Calendar.MONTH, month); // 增加或减少月份
//        return sdf.format(cal.getTime());
        return ZhyyDateUtil.addMonths(acctDay, month);
    }

    /**
     * 获取给定日期字符串 {@code acctDay} 所在**自定义周**的第一天的日期字符串 (yyyyMMdd)。
     * 自定义周的规则如下：
     * 1-7日：第一周，开始日期为01日。
     * 8-14日：第二周，开始日期为08日。
     * 15-21日：第三周，开始日期为15日。
     * 22-28日：第四周，开始日期为22日。
     * 29-31日：第五周，开始日期为29日。
     *
     * @param acctDay 期望格式为 "yyyyMMdd" 的日期字符串。
     * @return 给定日期所在自定义周的第一天的日期字符串，格式为 "yyyyMMdd"。
     */
    public static String getWeekStartV2(String acctDay) {
        SimpleDateFormat sdf = new SimpleDateFormat(YYYYMMDD_PATTERN);
        Date date;
        try {
            date = sdf.parse(acctDay); // 解析输入日期字符串
        } catch (ParseException e) {
            e.printStackTrace();
            date = new Date(); // 解析失败则使用当前日期
        }
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        String ymStr = acctDay.substring(0, 6); // 提取年月部分
        // String dayStr = acctDay.substring(7, 8); // 这一行是错误的，应该是 substring(6, 8)
        String dateStr = "";
        int dayInt = cal.get(Calendar.DATE); // 获取日期是当月的哪一天

        if (dayInt >= 1 && dayInt < 8) {
            dateStr = ymStr.concat("01"); // 1-7日，周开始为01日
        } else if (dayInt >= 8 && dayInt < 15) {
            dateStr = ymStr.concat("08"); // 8-14日，周开始为08日
        } else if (dayInt >= 15 && dayInt < 22) {
            dateStr = ymStr.concat("15"); // 15-21日，周开始为15日
        } else if (dayInt >= 22 && dayInt < 29) {
            dateStr = ymStr.concat("22"); // 22-28日，周开始为22日
        } else {
            dateStr = ymStr.concat("29"); // 29-31日，周开始为29日
        }
        try {
            date = sdf.parse(dateStr); // 解析计算出的周开始日期
        } catch (ParseException e) {
            e.printStackTrace();
            date = new Date(); // 解析失败则使用当前日期
        }
        cal.setTime(date);
        return sdf.format(cal.getTime());
    }

    /**
     * 根据给定日期字符串 {@code acctDay} 所在**自定义周**的最后一天。
     * 自定义周的规则如下：
     * 1-7日：最后一天为7日。
     * 8-14日：最后一天为14日。
     * 15-21日：最后一天为21日。
     * 22日及以后：最后一天为28日。
     * <p>
     * **注意：此方法在处理 "29-31日" 的情况时，直接返回 "28日"，这可能不符合预期，**
     * **因为它没有考虑实际月份的最后一天。例如，如果今天是30号，它会返回28号，而不是30号。**
     *
     * @param acctDay 期望格式为 "yyyyMMdd" 的日期字符串。
     * @return 给定日期所在自定义周的最后一天的日期字符串，格式为 "yyyyMMdd"。
     */
    public static String getWeekDay(String acctDay) {
        SimpleDateFormat sdf = new SimpleDateFormat(YYYYMMDD_PATTERN);
        Date date;
        try {
            date = sdf.parse(acctDay);
        } catch (ParseException e) {
            e.printStackTrace();
            date = new Date();
        }
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        String ymStr = acctDay.substring(0, 6); // 提取年月部分
        // String dayStr = acctDay.substring(7, 8); // 这一行是错误的，应该是 substring(6, 8)
        String dateStr = "";
        int dayInt = cal.get(Calendar.DATE); // 获取日期是当月的哪一天

        if (dayInt >= 1 && dayInt < 8) {
            dateStr = ymStr.concat("07"); // 1-7日，周结束为07日
        } else if (dayInt >= 8 && dayInt < 15) {
            dateStr = ymStr.concat("14"); // 8-14日，周结束为14日
        } else if (dayInt >= 15 && dayInt < 22) {
            dateStr = ymStr.concat("21"); // 15-21日，周结束为21日
        } else {
            dateStr = ymStr.concat("28"); // 22日及以后 (例如22-31日)，周结束为28日
        }
        try {
            date = sdf.parse(dateStr);
        } catch (ParseException e) {
            e.printStackTrace();
            date = new Date();
        }
        cal.setTime(date);
        return sdf.format(cal.getTime());
    }

    /**
     * **注意：此方法功能与名称不符。实际功能是获取给定日期当月所在自定义周的序号 (1-5)。**
     * 名称 {@code getWeekOfYear} 容易误解为获取一年中的第几周。
     * 内部的闰年判断和月份乘以5的逻辑也与标准“一年中的第几周”的计算方式不符。
     * <p>
     * **此方法实现逻辑错误，不能正确计算一年中的第几周或本月的第几周。**
     *
     * @param acctDay 期望格式为 "yyyyMMdd" 的日期字符串。
     * @return 返回的是一个自定义的周序号 (1-5)，而不是标准意义上的“一年中的第几周”。
     *         如果 month=1，则返回 {@code getDayOfWeek(day)} 的结果 (1-5)。
     *         如果 month=2，则返回 {@code getDayOfWeek(day) + 5} 的结果。
     *         如果 month > 2 且为闰年，则返回 {@code getDayOfWeek(day) + month * 5} 的结果。
     *         如果 month > 2 且非闰年，则返回 {@code getDayOfWeek(day) + month * 5 - 1} 的结果。
     */
    public static String getWeekOfYear(String acctDay) {
        String dayOfYear = "1";
        String year = acctDay.substring(0, 4);
        boolean isLeapYear = isLeapYear(Integer.parseInt(year)); // 判断是否闰年
        SimpleDateFormat sdf = new SimpleDateFormat(YYYYMMDD_PATTERN);
        Date date;
        try {
            date = sdf.parse(acctDay);
        } catch (ParseException e) {
            e.printStackTrace();
            date = new Date();
        }
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int month = cal.get(Calendar.MONTH) + 1; // 获取月份 (1-12)
        int day = cal.get(Calendar.DATE); // 获取日期 (几号)

        // **以下逻辑是自定义的，不符合标准周计算**
        if (month == 1) {
            dayOfYear = String.valueOf(getDayOfWeek(day)); // 如果是1月，返回当月第几周 (1-5)
        } else if (month == 2) {
            // 如果是2月，返回当月第几周 + 5
            dayOfYear = String.valueOf(getDayOfWeek(day) + 5);
        } else {
            if (isLeapYear) {
                // 如果是闰年且月份大于2，返回当月第几周 + 月份*5
                dayOfYear = String.valueOf(getDayOfWeek(day) + month * 5);
            } else {
                // 如果是非闰年且月份大于2，返回当月第几周 + 月份*5 - 1
                dayOfYear = String.valueOf(getDayOfWeek(day) + month * 5 - 1);
            }
        }
        return dayOfYear;
    }

    /**
     * 根据给定日期 {@code day} (当月第几天) 返回其所在的自定义周的序号。
     * 规则是：
     * 1-7日 -> 第1周
     * 8-14日 -> 第2周
     * 15-21日 -> 第3周
     * 22-28日 -> 第4周
     * 29-31日 -> 第5周
     *
     * @param day 当月的天数（1-31）。
     * @return 所在月份的自定义周序号 (1-5)。
     */
    public static int getDayOfWeek(int day) {
        int dayOfWeek = 1;
        if (day >= 1 && day < 8) {
            dayOfWeek = 1;
        } else if (day >= 8 && day < 15) {
            dayOfWeek = 2;
        } else if (day >= 15 && day < 22) {
            dayOfWeek = 3;
        } else if (day >= 22 && day < 29) {
            dayOfWeek = 4;
        } else {
            dayOfWeek = 5;
        }
        return dayOfWeek;
    }

    /**
     * 获取给定日期字符串 {@code acctDay} 所在**自定义周**的最后一天的日期字符串 (yyyyMMdd)。
     * 此方法在给定日期基础上简单地增加6天，作为自定义周的结束。
     * **注意：这里的“周”并不是标准意义上的完整一周，而是基于 `getWeekStartV2` 定义的日期区间。**
     *
     * @param acctDay 期望格式为 "yyyyMMdd" 的日期字符串，通常是 `getWeekStartV2` 的返回值。
     * @return 给定日期所在自定义周的最后一天的日期字符串，格式为 "yyyyMMdd"。
     */
    public static String getWeekEndV2(String acctDay) {
        SimpleDateFormat sdf = new SimpleDateFormat(YYYYMMDD_PATTERN);
        Date date;
        try {
            date = sdf.parse(acctDay);
        } catch (ParseException e) {
            e.printStackTrace();
            date = new Date();
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DATE, 6); // 在给定日期基础上加6天
        return sdf.format(calendar.getTime());
    }

    /**
     * 判断给定年份是否为闰年。
     * 闰年规则：能被4整除但不能被100整除，或者能被400整除。
     *
     * @param year 要判断的年份。
     * @return 如果是闰年返回 true，否则返回 false。
     */
    public static boolean isLeapYear(int year) {
        // 检查年份是否能被4整除且不能被100整除，或能被400整除
        return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
        // return ZhyyDateUtil.isLeapYear(year);
    }

    /**
     * 在给定日期字符串 {@code acctDay} (yyyyMMdd) 的基础上增加指定天数 {@code day}。
     * **特殊规则：如果增加天数后的“日”为29号，则将其转换为次月1号。**
     * 内部使用了 Hutool 的 {@code DateUtil.parse} 方法。
     *
     * @param acctDay 期望格式为 "yyyyMMdd" 的日期字符串。
     * @param day     要增加的天数。
     * @return 增加天数后的日期字符串，如果日为29则变为次月1号，格式为 "yyyyMMdd"。
     */
    public static String addDay3(String acctDay, int day) {
        SimpleDateFormat sdf = new SimpleDateFormat(YYYYMMDD_PATTERN);
        Calendar cal = Calendar.getInstance();
        cal.setTime(DateUtil.parse(acctDay, YYYYMMDD_PATTERN)); // 使用 Hutool 解析
        // int curMonth = cal.get(Calendar.MONTH); // 这行代码是多余的，未被使用
        cal.add(Calendar.DATE, day); // 增加天数
        int dayIndex = cal.get(Calendar.DATE); // 获取增加天数后的“日”
        if (dayIndex == 29) { // 如果是29号
            // 返回次月1日
            cal.add(Calendar.MONTH, 1); // 月份加1
            cal.set(Calendar.DAY_OF_MONTH, 1); // 设置为该月第一天
        }
        return sdf.format(cal.getTime());
    }
}
